﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using jSLCore.Client.Presentation.Common;
using jSLCore.Client.Utility;

namespace jSLCore.Client.Presentation.Common
{
    //Это заглушка, что б в SL проекте работало то, что работает в WPF проекте
}

namespace jSLCore.Utility.Extensions
{
    public static class TypeExpanderExtension
    {
        #region HasProperty
        private static bool SimpleHasProperty(this object obj, string property)
        {
            var propertyInfo = obj.GetType().GetProperty(property);
            return propertyInfo != null;
        }
        public static bool HasProperty(this object obj, string property)
        {
            if (obj == null) return false;
            if (String.IsNullOrEmpty(property)) return true;
            var indexOf = property.IndexOf(".");
            if (indexOf == -1) return obj.SimpleHasProperty(property);
            else
            {
                var firstObject = property.Substring(0, indexOf);
                if (!obj.SimpleHasProperty(firstObject)) return false;
                var fObject = obj.GetSimpleProperty(firstObject);
                var sbstr = property.Substring(indexOf + 1);
                return fObject.SimpleHasProperty(sbstr);
            }
        } 
        #endregion

        #region SetProperty
        
        private static void SetSimpleProperty(this object obj, string property, object value)
        {
            var propertyInfo = obj.GetType().GetProperty(property);
            if (propertyInfo != null)
            {

                propertyInfo.SetValue(obj, value, null);

            }
            else
            {
                throw new NotImplementedException(String.Format("Свойство {0} не найдено", property));
            }
        }

        public static void SetProperty(this object obj, string property, object value)
        {

            if (String.IsNullOrEmpty(property)) obj = value;
            else
            {
                var indexOf = property.IndexOf(".");
                if (indexOf == -1) obj.SetSimpleProperty(property, value);
                else
                {
                    var firstObject = property.Substring(0, indexOf);
                    var fObject = obj.GetSimpleProperty(firstObject);
                    var sbstr = property.Substring(indexOf + 1);
                    fObject.SetProperty(sbstr, value);
                }
            }
        } 
        #endregion

        #region GetProperty
      
        private static object GetSimpleProperty(this object obj, string property)
        {
            var propertyInfo = obj.GetType().GetProperty(property);
            if (propertyInfo != null)
            {

                object value = propertyInfo.GetValue(obj, null);
                return value;
            }
            else
            {
                throw new NotImplementedException(String.Format("Свойство {0} не найдено", property));
            }
        }

        public static TValType GetProperty<TValType>(this object obj, string property)
        {
            return (TValType)obj.GetProperty(property);
        }

        public static object GetPropertyOrNull(this object obj, string propName)
        {
            try
            {
                return obj.GetProperty(propName);
            }
            catch
            {
                return null;
            }
        }
        public static object GetProperty(this object obj, string property)
        {
            if (String.IsNullOrEmpty(property)) return obj;
            var indexOf = property.IndexOf(".");
            if (indexOf == -1) return obj.GetSimpleProperty(property);
            else
            {
                var firstObject = property.Substring(0, indexOf);
                var fObject = obj.GetSimpleProperty(firstObject);
                var sbstr = property.Substring(indexOf + 1);
                return fObject.GetProperty(sbstr);
            }
        } 
        #endregion

        public static object CastOrConvert(this object obj,Type toType)
        {
            if (obj == null) return obj;

            if (obj.GetType() == toType) return obj;

            
            if ((toType == typeof(Visibility)) && (obj is bool))
            {
                return (bool)obj? Visibility.Visible : Visibility.Collapsed;
            }
            else
            {
                ///Actually SilverLight does not provide it... but let it be for the future SL versions
                var typeConverterAttubute = toType.GetCustomAttributes(typeof(TypeConverterAttribute), true).LastOrDefault() as TypeConverterAttribute;
                if (typeConverterAttubute != null)
                {
                    var convType = Type.GetType(typeConverterAttubute.ConverterTypeName);
                    var constructorInfo = convType.GetConstructor(Type.EmptyTypes);
                    if(constructorInfo==null)throw new NotImplementedException("Trying to convert the value by type converter, which has no default constructor: "+convType.ToString());

                    var converter = (TypeConverter)constructorInfo.Invoke(new object[0]);

                    if(converter.CanConvertFrom(toType))
                    {
                        return converter.ConvertFrom(obj);
                    }
                }
                
                    
                    if (toType.IsEnum)
                    {

                        try
                        {
                            return Enum.Parse(toType, obj.ToString(), false);
                        }
                        catch (ArgumentException)
                        {

                            throw new SomethingInvalidException();
                        }

                    }
                    else
                    {
                        if (toType.IsGenericType)
                        {
                            if (toType.GetGenericArguments()[0].IsEnum)
                            {
                                try
                                {
                                    return Enum.Parse(toType.GetGenericArguments()[0], obj.ToString(), false);
                                }
                                catch (ArgumentException)
                                {

                                    throw new SomethingInvalidException();
                                }
                            }
                            else
                            {
                                if (toType.GetGenericTypeDefinition() == typeof (Nullable<>))
                                {
                                    if (obj is string)
                                        if(((string)obj)==string.Empty)
                                    {
                                        return null;
                                    }
                                    toType = toType.GetGenericArguments()[0];
                                }
                                if (obj is IConvertible)
                                {

                                    return ((IConvertible) obj).ToType(toType, null);
                                }
                                else
                                {
                                    return obj;//.ToString(); the same as below: why to string ??
                                }
                            }
                        }
                        else
                        {
                            if (toType == typeof (ImageSource) && obj is byte[])
                            {
                                return ((byte[])obj).ConvertToImageSource();
                            }
                            else
                            {

                                {
                                    if (obj is IConvertible)
                                    {
                                        return ((IConvertible) obj).ToType(toType, null);
                                    }
                                    else
                                    {
                                        return obj /*.ToString()Why to string??*/;
                                    }
                                }
                            }
                        }
                    }
            }
        }
        

        public static ImageSource ConvertToImageSource(this byte[] value)
        {
            //if(!(value is byte[]))throw new InvalidCastException("Необходимо передать byte[]");

            var bitmap = new BitmapImage();
            var memoryStream = new MemoryStream(value);
            bitmap.SetSource(memoryStream);
            memoryStream.Close();
            return bitmap;
        }

        public static string ToHHMMSS(this TimeSpan ts)
        {
            var mmss = string.Format("{0}:{1}",ts.Minutes,ts.Seconds.ToString().PadLeft(2,'0'));

            if(ts.Hours>0)
            {
                mmss = ts.Hours + ":" + mmss;
            }
            return mmss;
        }

        public static T[] ToArray2<T>(this ObservableCollection<T> source)
        {
            return ((IEnumerable<T>)source).ToArray();
        }

        public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> source)
        {
            var collection = new ObservableCollection<T>();
            foreach (var item in source)
            {
               
                collection.Add(item);
            }
            return collection;
        }

    }
}